package com.yhgarden.bbs.service.impl.system;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yhgarden.bbs.entity.system.BaseSelectItem;
import com.yhgarden.bbs.entity.system.Entity;
import com.yhgarden.bbs.entity.system.EntityProperty;
import com.yhgarden.bbs.mapper.system.BaseSelectItemMapper;
import com.yhgarden.bbs.mapper.system.DatabaseMapper;
import com.yhgarden.bbs.mapper.system.EntityMapper;
import com.yhgarden.bbs.mapper.system.EntityPropertyMapper;
import com.yhgarden.bbs.model.enums.StatusCode;
import com.yhgarden.bbs.model.helper.Pager;
import com.yhgarden.bbs.model.helper.SortPointer;
import com.yhgarden.bbs.model.response.BaseResponse;
import com.yhgarden.bbs.service.api.system.EntityPropertyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

@Service
public class EntityPropertyServiceImpl implements EntityPropertyService {

    @Value("${spring.application.name}")
    private String APPLICATION_NAME;

    @Autowired
    private EntityMapper entityMapper;

    @Autowired
    private EntityPropertyMapper entityPropertyMapper;

    @Autowired
    private DatabaseMapper databaseMapper;

    @Autowired
    private ExecutorService executorService;

    @Autowired
    private BaseSelectItemMapper selectItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse createOrUpdate(EntityProperty entityProperty) {
        BaseResponse response = new BaseResponse(StatusCode.SUCCESS);
        Entity entity = null;
        String entityId = entityProperty.getEntityId();
        if (entityId == null) {
            response = new BaseResponse(StatusCode.PARAMS_DEFICIENCY);
            return response;
        }
        entity = entityMapper.getById(entityId);
        if (entity == null) {
            response = new BaseResponse(StatusCode.NOT_FOUND_ENTITY);
            return response;
         }

        String tableName = entity.getTableName();
        String fieldName = entityProperty.getFieldName();
        String propertyId = entityProperty.getId();
        EntityProperty oldField = null;
        Future<EntityProperty> oldFieldFuture = null;
        if (propertyId == null) {
            entityPropertyMapper.getByTableNameAndFieldName(tableName, fieldName);
            oldFieldFuture = executorService.submit(() -> {
                return entityPropertyMapper.getByTableNameAndFieldName(tableName, fieldName);
            });
        } else {
            oldFieldFuture = executorService.submit(() -> {
                return entityPropertyMapper.getById(propertyId);
            });
        }
        entityPropertyMapper.getLastFieldByEntityId(entityId);
        Future<EntityProperty> lastFieldFuture = executorService.submit(() -> {
            return entityPropertyMapper.getLastFieldByEntityId(entityId);
        });

        BaseSelectItem selectItem = selectItemMapper.getById(entityProperty.getFieldType());

        EntityProperty lastField = null;
        try {
            oldField = oldFieldFuture.get();
            lastField = lastFieldFuture.get();
        } catch (InterruptedException e) {
            response = new BaseResponse(StatusCode.RUNTIME_PARALLEL_COMPUTE_ERROR);
            return response;
        } catch (ExecutionException e) {
            response = new BaseResponse(StatusCode.RUNTIME_PARALLEL_COMPUTE_ERROR);
            return response;
        }
        if (selectItem == null) {
            response = new BaseResponse(StatusCode.NOT_FOUND_SELECT_ITEM);
            return response;
        }
        String itemValueObj = selectItem.getItemValue();
        if (itemValueObj == null) {
            response = new BaseResponse(StatusCode.COMPLETENESS_DATA_ERROR);
            return response;
        }
        // 解析字段类型（用于数据库创建字段规定数据类型）
        String columnType = itemValueObj.toString();
        if (columnType.equals("varchar")) {
            Integer length = entityProperty.getFieldLength();
            if (length != null && length > 0) {
                columnType += "(" + entityProperty.getFieldLength() + ")";
            }
        }
//        String databaseName = T_DatabaseName.my_schema;
        String databaseName = APPLICATION_NAME;
        int res;
        if (oldField == null) {//该字段不存在，准备创建
            String uuid = UUID.randomUUID().toString();
            entityProperty.setId(uuid);
            entityPropertyMapper.create(entityProperty);
            //检查物理表是否存在此字段
            res = databaseMapper.checkTableColumn(databaseName, tableName, fieldName);
            if (res == 0) {//不存在，添加物理字段
                databaseMapper.alterTableAddColumn( tableName, entityProperty, columnType, lastField != null ? lastField.getFieldName() : null,  entityProperty.getDescription() );
            } else {//存在，修改字段
                databaseMapper.alterTableModifyColumn(tableName, entityProperty, columnType, lastField != null ? lastField.getFieldName() : null, entityProperty.getDescription());
            }
        } else {//改字段存在，准备修改
            entityProperty.setId(oldField.getId());
            entityPropertyMapper.update(entityProperty);
            res = databaseMapper.checkTableColumn(databaseName, tableName, oldField.getFieldName());
            if (res == 0) {
                databaseMapper.alterTableAddColumn(tableName, entityProperty, columnType, lastField != null ? lastField.getFieldName() : null,  entityProperty.getDescription());
            } else {
                if (oldField.getFieldName().equals(entityProperty.getFieldName())) {//旧字段跟修改字段同名，就是不改字段名
                    databaseMapper.alterTableModifyColumn(tableName, entityProperty, columnType, null, entityProperty.getDescription());
                } else {//旧字段跟修改字段不同名，就是要改字段名
                    databaseMapper.alterTableChangeColumn( tableName, oldField.getFieldName(), entityProperty, columnType, null, entityProperty.getDescription() );
                }
            }
        }
        response.setData(entityProperty);
        return response;
    }

    @Override
    public BaseResponse getById(String id) {
        BaseResponse response = new BaseResponse(StatusCode.SUCCESS);
        EntityProperty entityProperty = entityPropertyMapper.getById(id);
        response.setData(entityProperty);
        return response;
    }

    @Override
    public BaseResponse getByIdMoreDetail(String id) {
        BaseResponse response = new BaseResponse(StatusCode.SUCCESS);
        EntityProperty entityProperty = entityPropertyMapper.getByIdMoreDetail(id);
        response.setData(entityProperty);
        return response;
    }

    @Override
    public BaseResponse query(EntityProperty entityProperty) {
        BaseResponse response = new BaseResponse(StatusCode.SUCCESS);
        Pager pager = entityProperty.getPager();
        SortPointer sortPointer = entityProperty.getSortPointer();
        if(sortPointer == null){
            sortPointer = new SortPointer();
        }
        PageHelper.startPage(pager.getCurrentPage(),pager.getPageSize());
        List<EntityProperty> entityPropertyList = entityPropertyMapper.query(entityProperty,sortPointer.getOrder(),sortPointer.getField());
        PageInfo result = new PageInfo<EntityProperty>(entityPropertyList);
        response.setData(result);
        return response;
    }

    @Override
    public BaseResponse queryMoreDetail(EntityProperty entityProperty) {
        BaseResponse response = new BaseResponse(StatusCode.SUCCESS);
        Pager pager = entityProperty.getPager();
        SortPointer sortPointer = entityProperty.getSortPointer();
        if(sortPointer == null){
            sortPointer = new SortPointer();
        }
        PageHelper.startPage(pager.getCurrentPage(),pager.getPageSize());
        List<EntityProperty> entityPropertyList = entityPropertyMapper.queryMoreDetail(entityProperty,sortPointer.getOrder(),sortPointer.getField());
        PageInfo result = new PageInfo<EntityProperty>(entityPropertyList);
        response.setData(result);
        return response;
    }

    @Override
    public BaseResponse queryForList(EntityProperty entityProperty) {
        BaseResponse response = new BaseResponse(StatusCode.SUCCESS);
        Pager pager = entityProperty.getPager();
        SortPointer sortPointer = entityProperty.getSortPointer();
        if(sortPointer == null){
            sortPointer = new SortPointer();
        }
        PageHelper.startPage(pager.getCurrentPage(),pager.getPageSize());
        List<EntityProperty> entityPropertyList = entityPropertyMapper.queryForList(entityProperty,sortPointer.getOrder(),sortPointer.getField());
        PageInfo result = new PageInfo<EntityProperty>(entityPropertyList);
        response.setData(result);
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse delete(String id) {
        BaseResponse response = new BaseResponse(StatusCode.SUCCESS);
        //查询实体信息
        EntityProperty entityProperty = entityPropertyMapper.getById(id);
        if(entityProperty.getDeleted()){
            response = new BaseResponse(StatusCode.ENTITY_PROPERTY_HAS_DELETED);
            return response;
        }

        Entity entity = entityMapper.getById(entityProperty.getEntityId());
        if(entity.getDeleted()){
            response = new BaseResponse(StatusCode.ENTITY_HAS_DELETED);
            return response;
        }
        //先删除实体属性
        entityPropertyMapper.delete(id);
        //删除物理字段
        databaseMapper.alterTableDropColumn(entity.getTableName(),entityProperty.getFieldName());
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse batchDelete(String entityId, List<String> ids) {
        BaseResponse response = new BaseResponse(StatusCode.SUCCESS);
        List<EntityProperty> entityPropertyList = new ArrayList<>();
        ids.forEach(id->{
            EntityProperty entityProperty = entityPropertyMapper.getById(id);
            entityPropertyList.add(entityProperty);
        });
        //查询实体信息
        Entity entity = entityMapper.getById(entityId);
        //先批量删实体属性
        entityPropertyMapper.batchDelete(ids);
        //批量删除物理字段
        databaseMapper.alterTableDeleteColumn(entity.getTableName(),entityPropertyList);
        return response;
    }
}
